package com.example.axon.utils;

import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Protostuff {
    //避免每次序列化都重新申请Buffer空间
    private static final LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);


    /**
     * 使用pb进行序列化
     */
    @SuppressWarnings("ALL")
    public static <T> byte[] serialize(T entity) {
        Class clz = entity.getClass();
        return serialize(entity, clz);
    }

    /**
     * 使用pb进行序列化
     */
    public static <T> byte[] serialize(T entity, Class<T> clz) {
        try {
            Schema<T> schema1 = RuntimeSchema.getSchema(clz);
            return ProtostuffIOUtil.toByteArray(entity, schema1, buffer);
        } catch (Exception e) {
            log.error("failed to serialize entity!{}", entity);
            throw new IllegalStateException(e.getMessage(), e);
        } finally {
            buffer.clear();
        }
    }

    /**
     * 反序列化，将字节数组反序列化成指定Class类型（利用Unsafe对字段偏移量赋值，非java反射方式）
     */
    public static <T> T deserialize(byte[] data, Class<T> clazz) {
        Schema<T> schema = RuntimeSchema.getSchema(clazz);
        T obj = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(data, obj, schema);
        return obj;
    }

    /**
     * @param entity    旧的对象
     * @param builder   R(lombok注解的静态内部类实例)
     * @param <T>       被添加注解@Builder的外部类
     * @param <R>       lombok中的builder静态内部类
     * @return 返回一个基于老对象的builder
     */
    public static <T, R> R lombokBuilder(T entity, Class<R> builder) {
        byte[] serialize = Protostuff.serialize(entity);
        return Protostuff.deserialize(serialize, builder);
    }
}